function varargout = can_demo(varargin)
% CAN_DEMO MATLAB code for can_demo.fig
%      CAN_DEMO, by itself, creates a new CAN_DEMO or raises the existing
%      singleton*.
%
%      H = CAN_DEMO returns the handle to a new CAN_DEMO or the handle to
%      the existing singleton*.
%
%      CAN_DEMO('CALLBACK',hObject,eventData,handles,...) calls the local
%      function named CALLBACK in CAN_DEMO.M with the given input arguments.
%
%      CAN_DEMO('Property','Value',...) creates a new CAN_DEMO or raises the
%      existing singleton*.  Starting from the left, property value pairs are
%      applied to the GUI before can_demo_OpeningFcn gets called.  An
%      unrecognized property name or invalid value makes property application
%      stop.  All inputs are passed to can_demo_OpeningFcn via varargin.
%
%      *See GUI Options on GUIDE's Tools menu.  Choose "GUI allows only one
%      instance to run (singleton)".
%
% See also: GUIDE, GUIDATA, GUIHANDLES

% Edit the above text to modify the response to help can_demo

% Last Modified by GUIDE v2.5 20-Apr-2025 20:58:36

% Begin initialization code - DO NOT EDIT
gui_Singleton = 1;
gui_State = struct('gui_Name',       mfilename, ...
                   'gui_Singleton',  gui_Singleton, ...
                   'gui_OpeningFcn', @can_demo_OpeningFcn, ...
                   'gui_OutputFcn',  @can_demo_OutputFcn, ...
                   'gui_LayoutFcn',  [] , ...
                   'gui_Callback',   []);
if nargin && ischar(varargin{1})
    gui_State.gui_Callback = str2func(varargin{1});
end

if nargout
    [varargout{1:nargout}] = gui_mainfcn(gui_State, varargin{:});
else
    gui_mainfcn(gui_State, varargin{:});
end
% End initialization code - DO NOT EDIT


% --- Executes just before can_demo is made visible.
function can_demo_OpeningFcn(hObject, eventdata, handles, varargin)
% This function has no output args, see OutputFcn.
% hObject    handle to figure
% eventdata  reserved - to be defined in a future version of MATLAB
% handles    structure with handles and user data (see GUIDATA)
% varargin   command line arguments to can_demo (see VARARGIN)

% Choose default command line output for can_demo
handles.output = hObject;

% Update handles structure
guidata(hObject, handles);

% Initialize global variables
global CanOpened;
global savemat;
global savecnt;
global imagemat;  % 修改：使用cell数组存储图像数据
global imagecnt;  % 新增：图像数据计数器
global imageshowmat;  % 新增：GUI展示的图像数据
global imageshowcnt;  % 新增：GUI展示图像数据计数器
global DataSaveDir;  % 新增：日志保存目录
global logfilename;  % 新增：日志文件名
global logfileID;   % 新增：日志文件ID
global isImageCommand;  % 新增：是否为图像传输指令

% 初始化日志相关变量
baseDir = fullfile(pwd, 'logs');  % 基础日志目录
timeDir = datestr(now, 'yyyymmdd_HHMMSS');  % 时间戳作为文件夹名
DataSaveDir = fullfile(baseDir, timeDir);  % 完整的日志目录路径
logfilename = fullfile(DataSaveDir, 'log.txt');  % 日志文件路径
logfileID = -1;

% 确保基础日志目录存在
if ~exist(baseDir, 'dir')
    try
        mkdir(baseDir);
    catch ME
        error('无法创建基础日志目录: %s', ME.message);
    end
end

% 创建时间戳命名的日志目录
if ~exist(DataSaveDir, 'dir')
    try
        mkdir(DataSaveDir);
    catch ME
        error('无法创建日志目录: %s', ME.message);
    end
end

CanOpened = 0;  % Initialize CAN opened flag
savecnt = 1;    % Initialize save counter
imagecnt = 1;   % Initialize image counter
imageshowcnt = 1;  % 初始化GUI展示图像计数器
savemat = zeros(100000, 48);  % Pre-allocate matrix for 1000 sets of telemetry data
imagemat = {};  % 初始化cell数组
imageshowmat = {};  % 初始化GUI展示图像cell数组
isImageCommand = false;  % 初始化图像指令标志

% 初始化axes1和axes2
% 设置axes1
axes(handles.axes1);
title('X轴曲线');
grid on;
xlim([0 256]);
ylim([0 256]);
xlabel('X轴');
ylabel('强度');

% 设置axes2
axes(handles.axes2);
title('Y轴曲线');
grid on;
xlim([0 256]);
ylim([0 256]);
xlabel('Y轴');
ylabel('强度');

% 设置axes3
axes(handles.axes3);
grid on;
xlim([0 256]);
ylim([0 256]);
image_show = zeros(256, 256);
imshow(image_show);
title('太阳敏成像');
xlabel('太阳敏成像X轴');
ylabel('太阳敏成像Y轴');

% UIWAIT makes can_demo wait for user response (see UIRESUME)
% uiwait(handles.figure1);


% --- Outputs from this function are returned to the command line.
function varargout = can_demo_OutputFcn(hObject, eventdata, handles) 
% varargout  cell array for returning output args (see VARARGOUT);
% hObject    handle to figure
% eventdata  reserved - to be defined in a future version of MATLAB
% handles    structure with handles and user data (see GUIDATA)

% Get default command line output from handles structure
varargout{1} = handles.output;

% Clean up timers if they exist
if isfield(handles, 'telemetryTimer')
    if isvalid(handles.telemetryTimer)
        stop(handles.telemetryTimer);
        delete(handles.telemetryTimer);
    end
end

if isfield(handles, 'orderTimer')
    if isvalid(handles.orderTimer)
        stop(handles.orderTimer);
        delete(handles.orderTimer);
    end
end

% Clear workspace
clc; clear;


% --- Executes on button press in ConnectCAN.
function ConnectCAN_Callback(hObject, eventdata, handles)
% hObject    handle to ConnectCAN (see GCBO)
% eventdata  reserved - to be defined in a future version of MATLAB
% handles    structure with handles and user data (see GUIDATA)

global     savecnt;
savecnt=1;
rec = open_can();
if rec == 0
    LogShow('CAN连接成功');
    set(handles.log, 'String', '日志：CAN连接成功');
else
    LogShow('CAN连接失败');
    set(handles.log, 'String', '日志：CAN连接失败');
end

% --- Executes on button press in StartCAN.
function StartCAN_Callback(hObject, eventdata, handles)
% hObject    handle to StartCAN (see GCBO)
% eventdata  reserved - to be defined in a future version of MATLAB
% handles    structure with handles and user data (see GUIDATA)

rec = start_can();
if rec == 0
    LogShow('CAN启动成功');
    set(handles.log, 'String', '日志：CAN启动成功');
else
    LogShow('CAN启动失败');
    set(handles.log, 'String', '日志：CAN启动失败');
end

% --- Executes on button press in CloseCAN.
function CloseCAN_Callback(hObject, eventdata, handles)
% hObject    handle to CloseCAN (see GCBO)
% eventdata  reserved - to be defined in a future version of MATLAB
% handles    structure with handles and user data (see GUIDATA)

rec=close_can();
if rec == 0
    LogShow('CAN关闭成功');
    set(handles.log, 'String', '日志：CAN关闭成功');
else
    LogShow('CAN关闭失败');
    set(handles.log, 'String', '日志：CAN关闭失败');
end

% --- Executes on button press in OnceRemoteTelemetry.
function OnceRemoteTelemetry_Callback(hObject, eventdata, handles)
% hObject    handle to OnceRemoteTelemetry (see GCBO)
% eventdata  reserved - to be defined in a future version of MATLAB
% handles    structure with handles and user data (see GUIDATA)

data = '0AFFFF0000000000';
id = get(handles.InputID,'string');
reframes = 5;
retimeout = 200;
val1 = hexstr2num(data);
findata=val1;
Command_Deal(findata,id,reframes,retimeout);

% --- Executes on button press in ContinuousTelemetry.
function ContinuousTelemetry_Callback(hObject, eventdata, handles)
% hObject    handle to ContinuousTelemetry (see GCBO)
% eventdata  reserved - to be defined in a future version of MATLAB
% handles    structure with handles and user data (see GUIDATA)

% Get the current state of the button
button_state = get(hObject,'Value');

% Get the timer object from handles, or create a new one
if ~isfield(handles, 'telemetryTimer')
    % Create a new timer
    handles.telemetryTimer = timer(...
        'ExecutionMode', 'fixedRate', ...  % Run repeatedly
        'Period', 0.1, ...                % 10Hz = 0.1s period
        'TimerFcn', @(~,~)OnceRemoteTelemetry_Callback(hObject, eventdata, handles), ...
        'ErrorFcn', @(~,~)LogShow('Timer error occurred'), ...
        'Name', 'TelemetryTimer');
    
    % Save the timer in handles
    guidata(hObject, handles);
end

if button_state == 1
    % Start continuous telemetry
    start(handles.telemetryTimer);
    LogShow('Continuous telemetry started (10Hz)');
    set(hObject, 'String', '停止遥测');
else
    % Stop continuous telemetry
    stop(handles.telemetryTimer);
    LogShow('Continuous telemetry stopped');
    set(hObject, 'String', '连续遥测');
end

function InputID_Callback(hObject, eventdata, handles)
% hObject    handle to InputID (see GCBO)
% eventdata  reserved - to be defined in a future version of MATLAB
% handles    structure with handles and user data (see GUIDATA)

% Hints: get(hObject,'String') returns contents of InputVal as text
%        str2double(get(hObject,'String')) returns contents of InputVal as a double


% --- Executes during object creation, after setting all properties.
function InputID_CreateFcn(hObject, eventdata, handles)
% hObject    handle to InputID (see GCBO)
% eventdata  reserved - to be defined in a future version of MATLAB
% handles    empty - handles not created until after all CreateFcns called

% Hint: edit controls usually have a white background on Windows.
%       See ISPC and COMPUTER.
if ispc && isequal(get(hObject,'BackgroundColor'), get(0,'defaultUicontrolBackgroundColor'))
    set(hObject,'BackgroundColor','white');
end

% --- Executes on button press in SendOrderOnce.
function SendOrderOnce_Callback(hObject, eventdata, handles)
% hObject    handle to SendOrderOnce (see GCBO)
% eventdata  reserved - to be defined in a future version of MATLAB
% handles    structure with handles and user data (see GUIDATA)

data = get(handles.InputVal,'string');
id = get(handles.InputID,'string');
reframes = 5;
retimeout = 200;
val1 = hexstr2num(data);
findata=val1;
Command_Deal(findata,id,reframes,retimeout);

% --- Executes on button press in SendOrderContinuous.
function SendOrderContinuous_Callback(hObject, eventdata, handles)
% hObject    handle to SendOrderContinuous (see GCBO)
% eventdata  reserved - to be defined in a future version of MATLAB
% handles    structure with handles and user data (see GUIDATA)

% Get the current state of the button
button_state = get(hObject,'Value');

% Get the timer object from handles, or create a new one
if ~isfield(handles, 'orderTimer')
    % Create a new timer
    handles.orderTimer = timer(...
        'ExecutionMode', 'fixedRate', ...  % Run repeatedly
        'Period', 0.1, ...                % 10Hz = 0.1s period
        'TimerFcn', @(~,~)SendOrderOnce_Callback(hObject, eventdata, handles), ...
        'ErrorFcn', @(~,~)LogShow('Timer error occurred'), ...
        'Name', 'OrderTimer');
    
    % Save the timer in handles
    guidata(hObject, handles);
end

if button_state == 1
    % Start continuous order sending
    start(handles.orderTimer);
    LogShow('Continuous order sending started (10Hz)');
    set(hObject, 'String', '停止发送');
else
    % Stop continuous order sending
    stop(handles.orderTimer);
    LogShow('Continuous order sending stopped');
    set(hObject, 'String', '连续发送');
end

function InputVal_Callback(hObject, eventdata, handles)
% hObject    handle to InputVal (see GCBO)
% eventdata  reserved - to be defined in a future version of MATLAB
% handles    structure with handles and user data (see GUIDATA)

% Hints: get(hObject,'String') returns contents of InputVal as text
%        str2double(get(hObject,'String')) returns contents of InputVal as a double


% --- Executes during object creation, after setting all properties.
function InputVal_CreateFcn(hObject, eventdata, handles)
% hObject    handle to InputVal (see GCBO)
% eventdata  reserved - to be defined in a future version of MATLAB
% handles    empty - handles not created until after all CreateFcns called

% Hint: edit controls usually have a white background on Windows.
%       See ISPC and COMPUTER.
if ispc && isequal(get(hObject,'BackgroundColor'), get(0,'defaultUicontrolBackgroundColor'))
    set(hObject,'BackgroundColor','white');
end


% --- Executes on button press in SendImageOnce.
function SendImageOnce_Callback(hObject, eventdata, handles)
% hObject    handle to SendImageOnce (see GCBO)
% eventdata  reserved - to be defined in a future version of MATLAB
% handles    structure with handles and user data (see GUIDATA)

global isImageCommand;
global imagemat;
global imagecnt;
global DataSaveDir;

isImageCommand = true;  % 设置图像指令标志

data = '0A2B000100000000';
id = get(handles.InputID,'string');
reframes = 5;
retimeout = 200;
val1 = hexstr2num(data);
findata=val1;
Command_Deal(findata,id,reframes,retimeout);

% 处理图像数据
if ~isempty(imagemat) && imagecnt > 1
    frame_data = imagemat{imagecnt-1};
    frame_data_size = size(frame_data);
    if frame_data_size(1) >= 77
        % 数据排序
        sorted_data = sortrows(frame_data, 1);
        
        % 去除重复帧号的数据
        [~, unique_indices] = unique(sorted_data(:,1), 'stable');
        sorted_data = sorted_data(unique_indices, :);
        
        % 检查sorted_data的大小
        if size(sorted_data, 1) >= 75
            % 提取image_x数据
            imagex = [];
            for i = 2:38
                if i == 38  % 最后一帧
                    imagex = [imagex sorted_data(i, 2:4)];  % 只取2-4列
                else
                    imagex = [imagex sorted_data(i, 2:8)];  % 取2-8列
                end
            end
            
            % 提取image_y数据
            imagey = [];
            for i = 39:75
                if i == 75  % 最后一帧
                    imagey = [imagey sorted_data(i, 2:4)];  % 只取2-4列
                else
                    imagey = [imagey sorted_data(i, 2:8)];  % 取2-8列
                end
            end
            
            % 更新图像显示
            % 更新axes1
            set(handles.axes1, 'NextPlot', 'replacechildren');
            plot(handles.axes1, imagex);
            title(handles.axes1, 'X轴曲线');
            grid(handles.axes1, 'on');
            xlim(handles.axes1, [0 256]);
            ylim(handles.axes1, [0 256]);
            xlabel(handles.axes1, 'X轴');
            ylabel(handles.axes1, '强度');
            
            % 更新axes2
            set(handles.axes2, 'NextPlot', 'replacechildren');
            plot(handles.axes2, imagey);
            title(handles.axes2, 'Y轴曲线');
            grid(handles.axes2, 'on');
            xlim(handles.axes2, [0 256]);
            ylim(handles.axes2, [0 256]);
            xlabel(handles.axes2, 'Y轴');
            ylabel(handles.axes2, '强度');
            
            % 图像处理
            sum_x = sum(imagex);
            input_x_process = imagex - mean(imagex);
            input_x_process(input_x_process<10) = 0;
            input_x_process_T = transpose(input_x_process);
            input_y_process = imagey - mean(imagey);
            input_y_process(input_y_process<10) = 0;
            img_process_show = input_x_process_T * input_y_process / sum_x;
            
            % 更新axes3
            set(handles.axes3, 'NextPlot', 'replacechildren');
            imshow(img_process_show, [], 'Parent', handles.axes3);
            title(handles.axes3, '太阳敏成像');
            xlabel(handles.axes3, '太阳敏成像X轴');
            ylabel(handles.axes3, '太阳敏成像Y轴');
            
            % 保存GUI展示的图像数据
            global imageshowmat;
            global imageshowcnt;
            imageshowmat{imageshowcnt} = img_process_show;
            LogShow(sprintf('Saved GUI display image data set %d', imageshowcnt));
            imageshowcnt = imageshowcnt + 1;
            
            % 每100次保存一次GUI展示图像数据
            if mod(imageshowcnt, 100) == 0
                save(fullfile(DataSaveDir, 'imageshowmat.mat'), 'imageshowmat');
                LogShow('已保存GUI展示图像数据到文件');
            end
        end
    end
end

isImageCommand = false;  % 重置图像指令标志

% --- Executes on button press in SendImageContinuous.
function SendImageContinuous_Callback(hObject, eventdata, handles)
% hObject    handle to SendImageContinuous (see GCBO)
% eventdata  reserved - to be defined in a future version of MATLAB
% handles    structure with handles and user data (see GUIDATA)

% Get the current state of the button
button_state = get(hObject,'Value');

% Get the timer object from handles, or create a new one
if ~isfield(handles, 'imageTimer')
    % Create a new timer
    handles.imageTimer = timer(...
        'ExecutionMode', 'fixedRate', ...  % Run repeatedly
        'Period', 0.1, ...                % 10Hz = 0.1s period
        'TimerFcn', @(~,~)SendImageOnce_Callback(hObject, eventdata, handles), ...
        'ErrorFcn', @(~,~)LogShow('Timer error occurred'), ...
        'Name', 'ImageTimer');
    
    % Save the timer in handles
    guidata(hObject, handles);
end

if button_state == 1
    % Start continuous image sending
    start(handles.imageTimer);
    LogShow('Continuous image sending started (10Hz)');
    set(hObject, 'String', '停止传图');
else
    % Stop continuous image sending
    stop(handles.imageTimer);
    LogShow('Continuous image sending stopped');
    set(hObject, 'String', '连续传图');
end


%% 辅助函数：不涉及界面显示的函数
function Res = open_can()
%OPEN_CAN Initialize and open CAN device communication
%   This function opens and initializes the CAN device with specified parameters
%
% Returns:
%   Res = 0: Success - Device opened and initialized successfully
%   Res = 1: Initialization failed - Failed to initialize CAN parameters
%   Res = 2: Device open failed - Could not open CAN device
%
% Global Variables:
%   CanOpened - Flag indicating if CAN device is already open

global CanOpened;
% Initialize return value
Res = 0;

% Define device parameters
Device_type = 4;        % Hardware type identifier
Device_index = 0;       % Device index (first device)
Can_index = 0;         % CAN channel index

% Try to open device if not already opened
if CanOpened == 0
    VRec = VCI_OpenDevice(Device_type, Device_index, Can_index);
else
    VRec = 1;          % Device already opened
end

% If device opened successfully, configure it
if VRec
    % CAN bus configuration parameters
    Timing0 = 0;       % Timing register 0 (Baud rate related)
    Timing1 = 28;      % Timing register 1 (Baud rate related)
    Filter = 1;        % Filter mode
    Mode = 0;          % Normal mode
    Code = 0;          % Acceptance code
    Mask = 4294967295; % Acceptance mask (accept all)
    Reserved = 0;      % Reserved parameter

    % Combine configuration parameters
    InitConfig = [Code Mask Reserved Filter Timing0 Timing1 Mode];

    % Initialize CAN if not already initialized
    if CanOpened == 0
        if VCI_InitCAN(Device_type, Device_index, Can_index, InitConfig) ~= 1
            Res = 1;   % Initialization failed
        else
            CanOpened = 1;  % Set global flag
            Res = 0;        % Success
        end
    end
else
    Res = 2;          % Device open failed
end

function Res = close_can()
global CanOpened;
Res = 0;

Device_type = 4;
Device_index = 0;

if VCI_CloseDevice(Device_type,Device_index)~= 1
    msgbox('Failed to close CAN device','Error');
    Res = 1;
else
    CanOpened=0;
end

function Res = start_can()
% Start CAN communication
% Returns:
%   Res = 0: Success
%   Res = 1: Failed to start CAN
Device_type = 4;
Device_index = 0;
Can_index = 0; 

Res = 0;
if VCI_StartCAN(Device_type, Device_index, Can_index) ~= 1
    msgbox('Failed to strat CAN device', 'Error');
    Res = 1;
end


function Command_Deal(data,id,reframes,retimeout)
% Wrapper for backward compatibility
Command_Deal_Unified(data, id, reframes, retimeout, 1);

function Command_Deal_Unified(data, id, reframes, retimeout, command_type)
% Unified command processing function that combines Command_Deal, Command_Deal_Quick, and Command_Deal_Extern
% Parameters:
%   data: Command data to send
%   id: CAN ID
%   reframes: Expected response frames (only used for types that expect response)
%   retimeout: Response timeout (only used for types that expect response)
%   command_type: Command type (1=Standard, 2=Quick, 3=Extended)

% Prepare command type info
cmd_types = {'Standard', 'Quick', 'Extended'};
cmd_type_str = cmd_types{command_type};

% Log command initiation
if command_type == 2
    LogShow(sprintf('Processing %s CAN command: ID=0x%s, Data=[%s]', cmd_type_str, id, sprintf('%02X ', data)));
else
    LogShow(sprintf('Processing %s CAN command: ID=0x%s, Data=[%s], Expected frames=%d, Timeout=%d', ...
        cmd_type_str, id, sprintf('%02X ', data), reframes, retimeout));
end

% Calculate frame parameters
[~,slen] = size(data);
send_step = ceil(slen/8);  % Simplified calculation using ceil

% Send frames
remaining_len = slen;
for i = 1:send_step
    % Calculate frame size
    send_byte_num = min(remaining_len, 8);
    remaining_len = remaining_len - send_byte_num;
    
    % Extract data for this frame
    frame_start = 1 + (i-1)*8;
    frame_end = frame_start + send_byte_num - 1;
    frame_data = data(frame_start:frame_end);
    
    % Send frame based on command type
    if command_type == 3
        success = CanSendFrameExtern(hex2dec(id), frame_data, send_byte_num);
    else
        success = CanSendFrame(hex2dec(id), frame_data, send_byte_num);
    end
    
    % Log result
    if success
        LogShow(sprintf('%s frame %d/%d sent successfully: %d bytes', ...
            cmd_type_str, i, send_step, send_byte_num));
    else
        LogShow(sprintf('Failed to send %s frame %d/%d', cmd_type_str, i, send_step));
    end
end

% Handle response for non-quick commands
if command_type ~= 2
    % Wait for response with timeout
    LogShow(sprintf('Waiting for response (timeout: %d ms)...', retimeout));
    rec_ok_flag = CanRecTimeOutFast(reframes, retimeout);
    
    if rec_ok_flag == 1
        LogShow(sprintf('%s response timeout check passed', cmd_type_str));
        [frames,ids,recdata,datalen,RecOk] = Common_Receive();
        
        if RecOk == 1
            LogShow(sprintf('%s command completed: received %d frames, %d bytes', ...
                cmd_type_str, frames, datalen));
            
            % Process received data
            if ~isempty(recdata)
                % 移除显示接收数据的日志行
            end
        else
            LogShow(sprintf('%s command failed: receive error', cmd_type_str));
        end
    else
        LogShow(sprintf('%s command failed: timeout after %d ms', cmd_type_str, retimeout));
    end
else
    LogShow(sprintf('%s command completed - No response expected', cmd_type_str));
end


function LogShow(Istr)    
% 简单的日志记录函数
% 参数：
%   Istr: 要记录的日志信息

global logfileID;
global logfilename;

% 格式化时间戳
CurTime = sprintf('%04d-%02d-%02d %02d:%02d:%05.3f', clock);
LogStr = sprintf('%s %s\n', CurTime, Istr);

% 打印到命令窗口
fprintf(LogStr);

% 如果文件ID无效，打开新文件
if logfileID == -1
    try
        logfileID = fopen(logfilename, 'a');
        if logfileID == -1
            error('无法打开日志文件: %s', logfilename);
        end
    catch ME
        error('打开日志文件失败: %s', ME.message);
    end
end

% 写入日志文件
try
    fprintf(logfileID, '%s', LogStr);
catch ME
    error('写入日志文件失败: %s', ME.message);
end

function re = hexstr2num(instr)
% Convert hexadecimal string to decimal number
% Remove spaces from input string
instr = strrep(instr, ' ', '');

data1=[];
[m,~]=size(instr);
for i=1:m
    substr = instr(i,:);
    tran1=textscan(substr,'%02s');
    tran2=tran1{1};
    Fdata = hex2dec(tran2);
    send_data = Fdata';
    data1 = [data1 send_data];
end
re = data1;

function Success=CanSendFrame(id,send_data,dlc)
% Send a CAN frame with standard format
Device_type = 4;
Device_index = 0;
Can_index = 0; 
FrameFormat = 0;
FrameType = 0;
TimeStamp=0;
TimeFlag=0;
SendType=1;
SendNums=1;
Data = send_data(1:dlc);
Reserved=[0 0 0];

Frames=[id TimeStamp TimeFlag SendType FrameType FrameFormat dlc Data Reserved];
try
    Success = VCI_Transmit(Device_type,Device_index,Can_index, Frames,SendNums); % Send CAN frame
catch
    Success = 0; 
end

function rec_ok_flag = CanRecTimeOutFast(frames,RecTime)
Device_type = 4;
Device_index = 0;
Can_index = 0; 
m=0;
loop =0;
if RecTime==0
    CurRecTime=1;
else
    CurRecTime = RecTime;
end
while m<frames 
    try
        m = VCI_GetReceiveNum(Device_type,Device_index,Can_index);
    catch
    end
    %1ms
    DelayMsNoblock(10);
    loop = loop+1;
    if loop==CurRecTime
        rec_ok_flag =0;
        return;
    end
end
rec_ok_flag =1;

function DelayMsNoblock(time)
loop  = 100*time;
for i=1:5000
    for j =1:loop
    end
end

function [frames,ids,redata,datanum,Res] = Common_Receive()
% Receive CAN frames and process data
%
% Returns:
%   frames   - Number of frames received
%   ids      - Array of frame IDs
%   redata   - Array of received data
%   datanum  - Total number of data bytes
%   Res      - Operation result (1: Success, 0: Failed)

% Initialize return values
datanum = 0;
Res = 1;
redata = [];
ids = [];

% Define CAN device parameters
Device_type = 4;
Device_index = 0;
Can_index = 0;

% Try to receive CAN frames with timeout
try
    [GetLength, Frames] = VCI_Receive(Device_type, Device_index, Can_index, 100, 1000);
    
    % Log receive attempt
    LogShow(sprintf('Attempting to receive CAN frames... Timeout: 400ms'));
    
    % Check for valid frame length
    if GetLength == 0 || GetLength == hex2dec('FFFFFFFF')
        Res = 0;
        frames = GetLength;
        LogShow('No frames received or invalid frame length');
        return;
    end
    
    % Process received frames
    frames = GetLength;
    if GetLength > 0
        % Log successful reception
        LogShow(sprintf('Successfully received %d CAN frames', GetLength));
        
        % Pre-allocate arrays for better performance
        ids = zeros(1, GetLength);
        redata = zeros(1, GetLength * 8); % Maximum possible data length
        
        % Process each frame
        for i = 1:GetLength
            CurFrame = Frames(i,:);
            
            % Extract frame components
            ID = CurFrame(1);
            len = CurFrame(7);
            CurFrameData = CurFrame(8:(7+len));
            
            % Log frame details
            frameDataHex = sprintf('%02X ', CurFrameData);
            LogShow(sprintf('Frame %d: ID=0x%X, Length=%d, Data=[%s]', i, ID, len, frameDataHex));
            
            % Store frame data
            ids(i) = ID;
            startIdx = (i-1)*8 + 1;
            redata(startIdx:startIdx+len-1) = CurFrameData;
            datanum = datanum + len;
        end
        
        % Display all received data
        if ~isempty(redata)
            LogShow(sprintf('All received data: [%s]', sprintf('%02X ', redata)));
        end
        
        % Save telemetry data
        global savemat;
        global savecnt;
        global imagemat;
        global imagecnt;
        global DataSaveDir;
        global isImageCommand;
        
        if isImageCommand
            % 处理图像数据
            % 将接收到的数据重塑为帧数×8的矩阵
            num_frames = ceil(datanum / 8);
            frame_data = zeros(num_frames, 8);
            
            % 填充数据
            for i = 1:num_frames
                start_idx = (i-1)*8 + 1;
                end_idx = min(start_idx + 7, datanum);
                frame_data(i, 1:(end_idx-start_idx+1)) = redata(start_idx:end_idx);
            end
            
            % 将矩阵保存到cell数组中
            imagemat{imagecnt} = frame_data;
            LogShow(sprintf('Saved image data set %d with %d frames', imagecnt, num_frames));
            imagecnt = imagecnt + 1;
            
            % 每100次保存一次图像数据
            if mod(imagecnt, 100) == 0
                save(fullfile(DataSaveDir, 'imagemat.mat'), 'imagemat');
                LogShow('已保存图像数据到文件');
            end
            
            % 更新绘图
            frame_data_size = size(frame_data);
            if frame_data_size(1) >= 77
                disp(frame_data);
            end
        else
            % Save telemetry data
            if savecnt > size(savemat, 1)
                % Double the size of the matrix
                new_size = size(savemat, 1) * 2;
                temp = zeros(new_size, 48);
                temp(1:size(savemat, 1), :) = savemat;
                savemat = temp;
                LogShow(sprintf('Expanded save matrix to %d rows', new_size));
            end
            
            % Save the telemetry data
            savemat(savecnt, 1:min(datanum, 48)) = redata(1:min(datanum, 48));
            LogShow(sprintf('Saved telemetry data set %d with %d bytes', savecnt, min(datanum, 48)));
            savecnt = savecnt + 1;
            
            % 每100次保存一次遥测数据
            if mod(savecnt, 100) == 0
                save(fullfile(DataSaveDir, 'savemat.mat'), 'savemat');
                LogShow('已保存遥测数据到文件');
            end
        end
    end
catch ME
    % Handle errors
    Res = 0;
    frames = 0;
    LogShow(sprintf('CAN receive error: %s', ME.message));
end

% Log final status
if Res == 1
    LogShow(sprintf('CAN receive completed successfully. Total data bytes: %d', datanum));
else
    LogShow('CAN receive operation failed');
end
